#pragma once

#include <iostream>
#include <string>
#include <list>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>

#include "inetAddr.hpp"
#include "Log.hpp"
#include "Mutex.hpp"
using namespace LogModule;
using namespace LockModule;
// 观察者模式
// 观察者模式(发布订阅模式)是一种行为型设计模式，用于定义对象之间的一种一对多的依赖关系，
// 使得一个对象状态发生变化时，所有依赖它的对象都会收到通知并自动更新。
// 1.松耦合 : 观察者和被观察者之间是松耦合的，便于扩展和维护。
// 2.动态订阅 : 可以动态添加或移除观察者，灵活性高。
// 3.单向通信 : 被观察者通知观察者，观察者不能反向修改被观察者的状态。

class UserInterFace // 基类
{
public:
    virtual ~UserInterFace() = default;
    virtual void SendTo(int sockfd, const std::string &message) = 0;
    // 每一个子类都要支持发送消息和比较ip和port(后面添加删除用户要用)
    virtual bool operator==(const InetAddr &u) = 0;
    virtual std::string Id() = 0;
};
class User : public UserInterFace
{
public:
    User(const InetAddr &id)
        : _id(id)
    {
    }
    void SendTo(int sockfd, const std::string &message) override // 用户自己给自己发消息
    {
        LOG(Loglevel::INFO) << "send message to  " << _id.Addr() << "#" << message;
        int n = sendto(sockfd, message.c_str(), message.size(), 0, _id.NetAddr(), _id.NetAddrLen());
        (void)n;
    }
    bool operator==(const InetAddr &u) override
    {
        return _id == u;
    }
    std::string Id()
    {
        return _id.Addr();
    }
    ~User()
    {
    }

private:
    InetAddr _id; // 自己的addr
};
// 上面都是对User的描述
// 下面对在线的User进行管理
class UserManger
{
public:
    UserManger()
    {
    }
    // 添加用户

    // Router遍历链表转发消息的同时,可能来了新用户,AddUser也要对链表进行插入操作
    // 链表是公共资源,要进行保护
    void AddUser(InetAddr &id)
    {
        LockGard lock(_mutex);
        // 遍历列表,如果用户不存在就新建用户,如果存在直接返回
        for (auto &user : _online_user)
        {
            if (*user == id)
            {
                LOG(Loglevel::INFO) << id.Addr() << "该用户已存在";
                return;
            }
        }
        LOG(Loglevel::INFO) << "新增该用户" << id.Addr();
        _online_user.push_back(std::make_shared<User>(id));
        PrintfUser();
    }
    // 转发消息  //只需要把同一个消息让每个用户自己给自己发一遍就行了
    void Router(int sockfd, const std::string &message) // 路由
    {
        LockGard lock(_mutex);
        for (auto &user : _online_user)
        {
            user->SendTo(sockfd, message);
        }
    }
    // 删除用户
    void DelUser(InetAddr &id)
    {
        // v1
        auto pos = std::remove_if(_online_user.begin(), _online_user.end(), [&id](std::shared_ptr<UserInterFace> &user)
                                  { return *user == id; });
        _online_user.erase(pos, _online_user.end());
        PrintfUser();
    }
    void PrintfUser()
    {
        for (auto user : _online_user)
        {
            LOG(Loglevel::DEBUG) << "在线用户-> " << user->Id();
        }
    }
    ~UserManger()
    {
    }

private:
    std::list<std::shared_ptr<UserInterFace>> _online_user; // 在线用户
    Mutex _mutex;
};